import numpy as np
import struct
import matplotlib.pyplot as plt
import random
from sklearn.manifold import TSNE
from sklearn.decomposition import PCA
from sklearn.datasets import load_digits 
from sklearn.cluster import KMeans
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix,classification_report

#def init_count(ts,eps,minPts):

    
    #return count,cp_l

def add_wait(c_m,i,wait_l):
    for j in range(c_m.shape[0]):
        if i!=j:
            if c_m[i,j]!=0:
                if j not in wait_l:
                    wait_l.append(j)
    return wait_l

def my_dbscan(ts,eps,minPts):
    eps_m = np.zeros((ts.shape[0],ts.shape[0]))
    count = np.ones((ts.shape[0],1))
    cp_l = []
    bp_l = []
    np_l = []
    existed  = 0
    for i in range(ts.shape[0]):
        eps_m[i,i] = 1
        for j in range(i+1,ts.shape[0]):
            #print("i,j",i,j)
            d = np.linalg.norm(ts[i]-ts[j])
            if d<eps or d == eps:
                eps_m[i,j] = 1
                eps_m[j,i] = 1
                count[i] = count[i]+1
                count[j] = count[j]+1
        if count[i] > minPts or count[i] == minPts:
            cp_l.append(int(i))
    print("count",count)
    print("cp_l,cp_l.len",cp_l,len(cp_l))
    print("eps_m",eps_m)

    c_all_m = np.zeros((len(cp_l),eps_m.shape[1]))
    for i in range(len(cp_l)):
        for j in range(eps_m.shape[1]):
            c_all_m[i] = eps_m[cp_l[i]]
    print(" c_all_m")
    print( c_all_m, c_all_m.shape)
    
    c_m = np.zeros((len(cp_l),len(cp_l)))
    for i in range(len(cp_l)):
        for j in range(len(cp_l)):
            c_m[i,j] = eps_m[cp_l[i],cp_l[j]]
    print("c_m 1")
    print(c_m,c_m.shape)

    visited = set()
    clusters_n = 0
    wait_l = []
    clusters = set()
    final_clusters = []
    for i in range(c_m.shape[0]):
        clusters.clear()
        if i in visited:
            #print(i,"in visited:",visited)
            continue
        else:
            visited.add(i)
            clusters.add(i)
            wait_l = add_wait(c_m,i,wait_l)
            if len(wait_l) == 0:
                clusters_n = clusters_n+1
                final_clusters.append(list(clusters))
                print("final_clusters",final_clusters)
            else:
                while len(wait_l)!=0:
                    to_visited_n = wait_l.pop()
                    if to_visited_n in visited:
                        continue
                    else:
                        visited.add(to_visited_n)
                        clusters.add(to_visited_n)
                        wait_l = add_wait(c_m,to_visited_n,wait_l)
                clusters_n = clusters_n+1
                #print("clusters:",clusters)
                #print("visited:",visited)
                final_clusters.append(list(clusters))
                #print("final_clusters",final_clusters)

    print("clusters_n",clusters_n)
    print("final_clusters",final_clusters)

    fc_m = np.zeros((clusters_n,eps_m.shape[1]))
    for i in range(clusters_n):
        for j in final_clusters[i]:
            c1 = np.array(fc_m[i].astype(np.int))
            c2= np.array(c_all_m[j].astype(np.int))
            fc_m[i] = c1|c2
    print("fc_m,fc_m.shape",fc_m,fc_m.shape)
            
    return fc_m
                    

if __name__ == '__main__':

    digits = load_digits()
    ts = digits.data
    print("train_images1.shape",ts.shape)
    train_labels = digits.target
    print("train_labels.shape",train_labels.shape)
    print("Computing t-SNE embedding")
    tsne = TSNE(n_components=2, init='pca',random_state=0) #init='pca'
    train_image1_tsne = tsne.fit_transform(ts)
    print(train_image1_tsne)

    t_min, t_max = train_image1_tsne.min(0), train_image1_tsne.max(0)
    #print("t_min, t_max ",t_min, t_max)
    t_norm = (train_image1_tsne - t_min) / (t_max - t_min)  # 归一化
    print("t_norm",t_norm)
    ts = t_norm

    eps = 0.05
    minPts = 3
    
    clusters = my_dbscan(ts,eps,minPts)

    res_label = np.zeros(t_norm.shape[0])
    for i in range(clusters.shape[0]):
        for d in range(clusters.shape[1]):
            if clusters[i,d]!=0:
                #print("i,d",i,d)
                res_label[d] = i+1
                #print("res_label",d,"=",i)
                #print(res_label)

    res_label = res_label.astype(np.int)
    print("res_label",res_label)
    
    plt.figure(figsize=(6, 6))
    plt.scatter(ts[:,0],ts[:,1],c='k',marker='*')
    plt.xticks([])
    plt.yticks([])
    plt.show()

    colors = ['FIREBRICK','lightcoral','coral','gold','springgreen',
              'darkgreen','skyblue','steelblue','darkgrey','darkorchid']
    plt.figure(figsize=(6, 6))
    for i in range(ts.shape[0]):
        plt.text(ts[i, 0], ts[i, 1], str(res_label[i]-1), color=colors[(int(res_label[i])-1)%len(colors)], 
                 fontdict={'weight': 'bold', 'size': 9})#plt.cm.Set1(int(label_pred[i])
    #plt.scatter(final_centroids[:,0],final_centroids[:,1],c='k',marker='*')
    plt.xticks([])
    plt.yticks([])
    plt.show()






    

